﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace PKSpeed
{
    /// <summary>
    /// 附加操作
    /// </summary>
    class ExtraOperation
    {
        /// <summary>
        /// 退出程序
        /// </summary>
        /// <param name="commandArg">参数均为空</param>
        /// <param name="args">参数均为空</param>
        /// <param name="outFileName">参数均为空</param>
        /// <param name="grepArg">参数均为空</param>
        /// <returns></returns>
        public static bool Exit(String commandArg, List<String> args, String outFileName, List<String> grepArg)
        {
            Environment.Exit(0);
            return true;
        }

        /// <summary>
        /// 添加等效命令
        /// </summary>
        /// <param name="commandArg">应该为空</param>
        /// <param name="args">等效命令的参数</param>
        /// <param name="outFileName">应该为空</param>
        /// <param name="grepArg">应该为空</param>
        /// <returns>是否成功</returns>
        public static bool Alias(String commandArg, List<String> args, String outFileName, List<String> grepArg)
        {
            if (!String.IsNullOrEmpty(commandArg) || !String.IsNullOrEmpty(outFileName)
                || grepArg.Count != 0 || args.Count == 0)//如果这些参数不为空
            {
                Console.WriteLine("错误的命令格式！");
                return false;
            }
            String arg = args.Aggregate("", (current, a) => current + a + " ");//合并参数便于分析
            arg = Regex.Replace(arg, "[\\s]{0,}=[\\s]{0,}", "=");
            arg = Regex.Replace(arg, "[\\s]{1,}$", "");
            int equal = arg.IndexOf('=');//等号位置
            int equalCount = arg.LastIndexOf('=');//如果两个位置相同，则只有一个等号
            int firstQuot = arg.IndexOf('\'');//第一个'
            int lastQuot = arg.LastIndexOf('\'');//第二个'
            int countQuot = arg.Count(a => a == '\'');//'的个数
            if (countQuot != 2 || equal != equalCount || equal < 1 || equal >= arg.Length - 2 || 
                firstQuot != equal + 1 || lastQuot != arg.Length - 1)//如果参数输入不符合要求
            {
                Console.WriteLine("错误的参数格式！");
                return false;
            }
            String[] cmds = arg.Split('=');
            if (cmds[0].Any(c => !(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')))//如果等效命令中有非法字符
            {
                Console.WriteLine("错误的等效命令格式！");
                return false;
            }
            if(HashCommand.GetHashCode(cmds[0]) != -1)//如果为系统命令
            {
                Console.WriteLine("不可以使用系统命令作为等效命令名称！");
                return false;
            }
            if(AliasConfiguration.AddAliasCommand(Program.CurrentCommand.CurrentUser, cmds[0], cmds[1].Replace("\'","")))
            {
                Console.WriteLine("添加成功！");
                return true;
            }
            Console.WriteLine("已存在该等效命令，是否覆盖？\n1.是\n2.否");
            String s = Console.ReadLine();
            while(s != "1" && s != "2")
            {
                s = Console.ReadLine();
            }
            if (s == "1")
            {
                if (AliasConfiguration.ModifyAliasCommand(Program.CurrentCommand.CurrentUser, cmds[0],
                                                          cmds[1].Replace("\'", "")))
                {
                    Console.WriteLine("替换成功！");
                    return true;
                }
                Console.WriteLine("替换失败！");
                return false;

            }
            return true;
        }


        /// <summary>
        /// Alias等效替换
        /// </summary>
        /// <param name="cmdStr">原命令</param>
        /// <returns>替换后的命令</returns>
        public static String AliasRecovery(String cmdStr)
        {
            cmdStr = Regex.Replace(cmdStr, "^[\\s]{0,}", "");//去除前边的空格
            int space = cmdStr.IndexOf(' ');
            String cmdName = cmdStr;//命令的名称
            if (space != -1)
            {
                cmdName = cmdStr.Substring(0, space);
            }
            while (HashCommand.GetHashCode(cmdName) == -1)//如果不是原始命令
            {
                String aliasCmd = AliasConfiguration.GetOldCommand(Program.CurrentCommand.CurrentUser, cmdName);
                if (String.IsNullOrEmpty(aliasCmd))//如果不存在
                {
                    return cmdStr;
                }
                cmdStr = Regex.Replace(cmdStr, "^" + cmdName, aliasCmd);
                space = cmdStr.IndexOf(' ');
                cmdName = cmdStr;//命令的名称
                if (space != -1)
                {
                    cmdName = cmdStr.Substring(0, space);
                }
            }
            return cmdStr;
        }

        /// <summary>
        /// TAB智能提示
        /// </summary>
        /// <param name="sourceCmdStr">原串</param>
        /// <param name="secondTab">是否补充最长匹配后的第二次按TAB</param>
        /// <param name="tabCount">TAB键计数</param>
        /// <returns>结果</returns>
        public static String Tab(String sourceCmdStr, bool secondTab, ref int tabCount)
        {
            String cmdStr = AliasRecovery(Regex.Replace(sourceCmdStr, "^[\\s]{1,}", ""));
            String spaceStr = sourceCmdStr.Substring(0, sourceCmdStr.IndexOf(Regex.Replace(sourceCmdStr, "^[\\s]{1,}", "")));
            if (String.IsNullOrEmpty(cmdStr)) //如果当前输入串为空
            {
                ConsoleColor oldColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Blue;
                Console.WriteLine(
                    "\n{0,-15}{1,-15}\n{2,-15}{3,-15}\n{4,-15}{5,-15}\n{6,-15}{7,-15}\n{8,-15}{9,-15}\n{10,-15}{11,-15}\n{12,-15}{13,-15}",
                    "alias", "cat", "cd", "cp", "exit", "find", "logout", "ls", "mkdir", "mv", "passwd", "rm", "su",
                    "useradd");
                Console.ForegroundColor = oldColor;
                //打印等效命令
                List<String> aliasCmds = AliasConfiguration.GetAllCommand(Program.CurrentCommand.CurrentUser);
                if (aliasCmds != null)
                {
                    aliasCmds = StringOrderByAsc(aliasCmds);
                    for(int j = 0; j<aliasCmds.Count; j++)
                    {
                        Console.Write("{0,-15}",aliasCmds[j++]);
                        if(j<aliasCmds.Count)
                        {
                            Console.Write("{0,-15}",aliasCmds[j]);
                        }
                        Console.Write("\n");
                    }
                }
                return sourceCmdStr;
            }
            int i = 0;
            while (cmdStr[i] != ' ') //命令是否输完
            {
                i++;
                if (i == cmdStr.Length) //命令还没有输完，需要补充
                {
                    String[] cmds = {
                                        "useradd", "passwd", "su", "logout", "ls", "cp", "mv", "mkdir", "cd", "rm",
                                        "cat", "find", "exit", "alias"
                                    };
                    List<String> allCmds = new List<string>();
                    allCmds.AddRange(StringOrderByAsc(cmds.ToList()));
                    //添加等效命令到集合中
                    List<String> aliasCmds = AliasConfiguration.GetAllCommand(Program.CurrentCommand.CurrentUser);
                    if (aliasCmds != null)
                    {
                        allCmds.AddRange(StringOrderByAsc(aliasCmds));
                    }
                    String sameHead = GetSameHeadStr(allCmds, cmdStr, ref tabCount);//公共子前缀
                    if (secondTab)//如果是第二次按下TAB键
                    {
                        ConsoleColor oldColor = Console.ForegroundColor;
                        for (int k = 0; k < allCmds.Count; k++)
                        {
                            if (cmds.Contains(allCmds[k]))
                            {
                                Console.ForegroundColor = ConsoleColor.Blue;//高亮输出系统命令
                            }
                            Console.Write("\n{0,-15}", allCmds[k++]);
                            if (k < allCmds.Count)
                            {
                                if(cmds.Contains(allCmds[k]))
                                {
                                    Console.ForegroundColor = ConsoleColor.Blue;//高亮输出系统命令
                                }
                                Console.Write("{0,-15}", allCmds[k]);
                            }
                            Console.ForegroundColor = oldColor;
                        }
                        Console.Write("\n");
                    }
                    return spaceStr + sameHead;
                }
            }
            String command ="";//当前命令
            for (int j = 0; j < i; j++)
            {
                command += cmdStr[j];
            }
            while (cmdStr[i] == ' ') //忽略多余的空格
            {
                i++;
                if (i == cmdStr.Length) //如果命令后边是空格结束
                {
                    if (command == "find" || command == "cd" || command == "ls")
                    {
                        PrintFiles("C:" + Program.CurrentCommand.CurrentPath, true);
                    }
                    else if (command == "cp" || command == "mv" || command == "rm" || command == "cat")
                    {
                        PrintFiles("C:" + Program.CurrentCommand.CurrentPath, false);
                    } 
                    tabCount = 0;
                    return sourceCmdStr;
                }
            }
            if (cmdStr[i] == '-') //忽略'-'参数
            {
                while (cmdStr[i] != ' ')
                {
                    i++;
                    if (i == cmdStr.Length) //如果命令后边是参数结束
                    {
                        tabCount = 0;
                        return sourceCmdStr;
                    }
                }
                while (cmdStr[i] == ' ') //忽略多余的空格
                {
                    i++;
                    if (i == cmdStr.Length) //如果命令后边是空格结束
                    {
                        if (command == "cd" || command == "ls")
                        {
                            PrintFiles("C:" + Program.CurrentCommand.CurrentPath, true);
                        }
                        else if (command == "find" || command == "cp" || command == "mv" || command == "rm" || command == "cat")
                        {
                            PrintFiles("C:" + Program.CurrentCommand.CurrentPath, false);
                        }
                        tabCount = 0;
                        return sourceCmdStr;
                    }
                }
            }
            while (cmdStr[i] != '>' && cmdStr[i] != '|') //如果是命令参数
            {
                int j = i; //参数起始位置
                while (cmdStr[i] != ' ')
                {
                    i++;
                    if (i == cmdStr.Length) //如果参数没有输入完毕
                    {
                        String arg = ""; //当前参数
                        for (int k = j; k < i; k++)
                        {
                            arg += cmdStr[k];
                        }
                        //参数中的路径部分
                        String argPath = arg.LastIndexOf('/') >= 0 ? arg.Substring(0, arg.LastIndexOf('/')) : "";
                        String curPath = Program.CurrentCommand.CurrentPath == "/"
                                             ? ""
                                             : Program.CurrentCommand.CurrentPath;
                        String truePath = argPath.IndexOf('/') == 0
                                      ? "C:" + argPath
                                      : "C:" + curPath + "/" + argPath;
                        //参数中需要补全的部分
                        if(arg.LastIndexOf('/')+1==arg.Length)//如果路径已经输入完毕
                        {
                            if (command == "cd" || command == "ls")
                            {
                                PrintFiles("C:" + Program.CurrentCommand.CurrentPath, true);
                            }
                            else if (command == "find" || command == "cp" || command == "mv" || command == "rm" || command == "cat")
                            {
                                PrintFiles("C:" + Program.CurrentCommand.CurrentPath, false);
                            }
                            tabCount = 0;
                            return sourceCmdStr;
                        }
                        String argTo = arg.LastIndexOf('/') >= 0 ? arg.Substring(arg.LastIndexOf('/') + 1) : arg;
                        //得到路径下边的文件夹信息
                        var dir = new DirectoryInfo(truePath);
                        List<String> fileInfo = (from nextDirectory in dir.GetDirectories()
                                        where !FileOperation.IsHiddenDir(nextDirectory)
                                        select nextDirectory.Name).ToList();
                        //排序
                        fileInfo = StringOrderByAsc(fileInfo);
                        //如果命令后边的参数只能是目录
                        if(command == "cd" || command == "ls")
                        {
                            String sameHead = GetSameHeadStr(fileInfo, argTo, ref tabCount);
                            if (fileInfo.Count==1 && Directory.Exists(truePath + "/" + sameHead))
                            {
                                tabCount = 0;
                                return Regex.Replace(cmdStr, argTo + "$","") + sameHead + "/";
                            }
                            if(secondTab)//如果是第二次按下TAB键
                            {
                                ConsoleColor oldColor = Console.ForegroundColor;
                                Console.ForegroundColor = ConsoleColor.Blue;
                                for (int k = 0; k < fileInfo.Count; k++)
                                {
                                    Console.Write("\n{0,-15}", fileInfo[k++]);
                                    if(k < fileInfo.Count)
                                    {
                                        Console.Write("{0,-15}", fileInfo[k]);
                                    }
                                }
                                Console.Write("\n");
                                Console.ForegroundColor = oldColor;
                            }
                            return Regex.Replace(sourceCmdStr, argTo + "$","") + sameHead;
                        }
                        //添加路径下边的文件信息
                        List<String> files = StringOrderByAsc((from nextFile in dir.GetFiles()
                                              where !FileOperation.IsHiddenFile(nextFile)
                                              select nextFile.Name).ToList());
                        files.AddRange(fileInfo);
                        fileInfo = files;
                        if (command == "find" || command == "cp" || command == "mv" || command == "rm" || command == "cat")
                        {
                            String sameHead = GetSameHeadStr(fileInfo, argTo, ref tabCount);
                            if (fileInfo.Count > 1)
                            {
                                if (secondTab)//如果是第二次按下TAB键
                                {
                                    ConsoleColor oldColor = Console.ForegroundColor;
                                    for (int k = 0; k < fileInfo.Count; k++)
                                    {
                                        Console.ForegroundColor = Directory.Exists(truePath + "/" + fileInfo[k])
                                                                      ? ConsoleColor.Blue
                                                                      : oldColor;
                                        Console.Write("\n{0,-15}", fileInfo[k++]);
                                        if (k < fileInfo.Count)
                                        {
                                            Console.ForegroundColor = Directory.Exists(truePath + "/" + fileInfo[k])
                                                                          ? ConsoleColor.Blue
                                                                          : oldColor;
                                            Console.Write("{0,-15}", fileInfo[k]);
                                        }
                                    }
                                    Console.Write("\n");
                                    Console.ForegroundColor = oldColor;
                                }
                            }
                            if (fileInfo.Count == 1 && Directory.Exists(truePath + "/" + sameHead))//如果匹配结果是目录
                            {
                                tabCount = 0;
                                return Regex.Replace(sourceCmdStr, argTo + "$", "") + sameHead + "/";
                            }
                            return Regex.Replace(sourceCmdStr, argTo + "$", "") + sameHead;
                        }
                        return sourceCmdStr;
                    }
                }
                while (cmdStr[i] == ' ') //忽略多余的空格
                {
                    i++;
                    if (i == cmdStr.Length) //如果参数后边是空格结束
                    {
                        if (command == "cd" || command == "ls")
                        {
                            PrintFiles("C:" + Program.CurrentCommand.CurrentPath, true);
                        }
                        else if (command == "find" || command == "cp" || command == "mv" || command == "rm" || command == "cat")
                        {
                            PrintFiles("C:" + Program.CurrentCommand.CurrentPath, false);
                        }
                        tabCount = 0;
                        return sourceCmdStr;
                    }
                }
            }
            tabCount = 0;
            return sourceCmdStr;
        }

        //获得最长公共子前缀
        private static String GetSameHeadStr(List<String> strList, String subStr, ref int tabCount)
        {
            string str = subStr;
            List<String> toRemove = strList.Where(s => s.IndexOf(str) != 0).ToList();
            foreach (var s in toRemove)
            {
                strList.Remove(s);
            }
            if(strList.Count == 0)//如果没有以该子串开头的
            {
                tabCount = 0;
                return subStr;
            }
            if(strList.Count == 1)//如果只有一个
            {
                tabCount = 0;
                return strList[0];
            }
            for(int i = subStr.Length;;i++)
            {
                if(i<strList[0].Length)
                {
                    char c = strList[0][i];
                    for(int j = 1; j< strList.Count; j++)
                    {
                        if(strList[j].Length == i || strList[j][i] != c)//最长匹配结束
                        {
                            return subStr;
                        }
                    }
                    subStr += c;//如果都含有c  则添加
                }
                if(i==strList[0].Length)
                {
                    return subStr;
                }
            }
        }
        
        //打印当前目录下所有的目录和文件
        private static void PrintFiles(String currentPath, bool isOnlyDirectories)
        {
            var dir = new DirectoryInfo(currentPath);
            //添加目录信息
            List<String> fileInfo = (from nextDirectory in dir.GetDirectories()
                                     where !FileOperation.IsHiddenDir(nextDirectory)
                                     select nextDirectory.Name).ToList();
            fileInfo = StringOrderByAsc(fileInfo);
            if (!isOnlyDirectories)
            {
                //添加文件信息
                List<String> files = StringOrderByAsc((from nextFile in dir.GetFiles()
                                                    where !FileOperation.IsHiddenFile(nextFile)
                                                    select nextFile.Name).ToList());
                files.AddRange(fileInfo);
                fileInfo = files;
            }
            //原来的前景色
            ConsoleColor oldColor = Console.ForegroundColor;
            //打印所有的文件
            for (int k = 0; k < fileInfo.Count; k++)
            {
                //目录以蓝色打印
                Console.ForegroundColor = Directory.Exists(currentPath + "/" + fileInfo[k])
                                              ? ConsoleColor.Blue
                                              : oldColor;
                Console.Write("\n{0,-15}", fileInfo[k++]);
                if (k < fileInfo.Count)
                {
                    //目录以蓝色打印
                    Console.ForegroundColor = Directory.Exists(currentPath + "/" + fileInfo[k])
                                                  ? ConsoleColor.Blue
                                                  : oldColor;
                    Console.Write("{0,-15}", fileInfo[k]);
                }
            }
            Console.Write("\n");
            Console.ForegroundColor = oldColor;
        }

        //LINQ字符串排序
        private static List<String> StringOrderByAsc(List<String> source)
        {
            return source.OrderBy(s =>
            {
                double res = 0;
                double f = 0.01f;
                foreach (char c in s)
                {
                    res += (c - ' ') * f;
                    f *= 0.01f;
                }
                return res;
            }).ToList();
        }
    }
}
